/*
 * RTSAI - Real-Time Strategy engine for AI research
 * Copyright(C) 2006 DIMAp-UFRN, licensed under LGPL
 *
 * RTSAI Full Capture-the-Flag Application
 */

#include <sstream>

#include <GL/glut.h>

#include "rtsai.h"
#include "Common.h"
#include "GameView.h"
#include "UnitState.h"
#include "GameEvent.h"
#include "Log.h"

// colors for all the units of a player
const Vector3D colors[] = {
    Vector3D ( 1.0f, 1.0f, 1.0f ),     // flag color
    Vector3D ( 0.7f, 0.7f, 0.5f ),     // p1 color
    Vector3D ( 0.5f, 0.7f, 0.7f )      // p2 color
};

// colors for checkboard
const Vector3D terrain_color[] = {
    Vector3D ( 0.27f, 0.27f, 0.27f ),    // p1 terrain color
    Vector3D ( 0.30f, 0.30f, 0.30f )     // p2 terrain color
};


// messages in the view overlay
const Vector3D overlay_color = Vector3D ( 1, 0, 0 );
const Vector3D overlay[] = {
    Vector3D ( 5, 35, 0 ),
    Vector3D ( 5, 20, 0 ),
    Vector3D ( 5, 05, 0 )
};

char *gamefile;


/** re-start the game */
void reset_game()
{
    Lua::reset();
    Game::getInstance().reset();
    Game::getInstance().init(gamefile);
}


/** get a player score, stored in lua */
int get_score ( Player &p )
{
    string name = p.get_name();
    string lua_score = "game.players." + name + ".score";
    return Lua::get_integer (lua_score);
}


/** set a player score in lua */
void set_score ( Player &p, int s )
{
    string name = p.get_name();
    string lua_score = "game.players." + name + ".score";
    return Lua::set_integer (lua_score, s);
}


/** callback for updating the graphical window. it's called on each iteration */
void view_update()
{
    Game& game = Game :: getInstance();

    std::ostringstream score_str[2];

    // draw players teams
    Pool < Player > players = game.get_players();
    foreach ( pl, players )
    {
        // variable to consult the player score in lua
        int id = (*pl).get_id();
        int score = get_score (*pl);
        score_str[id] << (*pl).get_name() << ": " << score;

        Pool < Unit > units = (*pl).get_units();
        foreach ( u, units )
        {
            GameView::drawVehicle ((*u), colors [ id + 1 ]);
        }
    }

    // draw obstacles
    ObjectList *objects = game.get_objs();
    for ( ObjectList::iterator obj = objects->begin() ; obj != objects->end() ; ++obj )
    {
        // TODO this a dependency of OpenSteer library
        GameObject *gobj = dynamic_cast < GameObject* > ( *obj );
        GameView::drawObject ((*gobj), colors [ 0 ]);
    }

    glPushAttrib (GL_ENABLE_BIT);
    glDisable (GL_CULL_FACE);
    OpenSteer::drawQuadrangle (
        Vector3D ( -50, -0.1, 30 ),
        Vector3D (  50, -0.1, 30 ),
        Vector3D (  50, -0.1,  0 ),
        Vector3D ( -50, -0.1,  0 ),
        Vector3D ( 0.27f, 0.27f, 0.27f )
    );

    OpenSteer::drawQuadrangle (
        Vector3D ( -50, -0.1,   0 ),
        Vector3D (  50, -0.1,   0 ),
        Vector3D (  50, -0.1, -30 ),
        Vector3D ( -50, -0.1, -30 ),
        Vector3D ( 0.2f, 0.2f, 0.2f )
    );
    glPopAttrib ();

    int sc = Lua::get_integer ("seeker_count");
    int fc = Lua::get_integer ("flag_count");

    std::ostringstream tm_str;
    tm_str << "Elapsed time: " << game.current_time;

    OpenSteer :: draw2dTextAt2dLocation (score_str[0], overlay[0], overlay_color);
    OpenSteer :: draw2dTextAt2dLocation (score_str[1], overlay[1], overlay_color);
    OpenSteer :: draw2dTextAt2dLocation (tm_str, overlay[2], overlay_color);
}


/** class to handle when a flag is captured */
class EventHandle : public UnitState
{
    UnitState* react_to_event ( const string &event_name, GameEventData *data ) {
        /*
        int sc = Lua::get_integer ("seeker_count");
        int fc = Lua::get_integer ("flag_count");
        */

        std::map < Player*, int > scores;

        std::ostringstream score_str[2];


        // save the players score
        Pool < Player > players = Game::getInstance().get_players();
        foreach ( pl, players )
        {
            scores[&(*pl)] = get_score (*pl);

            /*
            // variable to consult the player score in lua
            int id = (*pl).get_id();
            int score = get_score (*pl);

            string lua_score = "game.players." + name + ".score";
            int score = Lua::get_integer (lua_score);
            score_str[id] << name << ": " << score;
            */
        }

        // re-start the game
        reset_game();

        // adding handler to the game events
        GameEvent *flag_event = Game::getInstance().get_event ( "flag_captured" );
        flag_event->add_listener ( this );

        // update the old players score
        foreach ( sc, scores )
        {
            set_score ( *((*sc).first), (*sc).second );
        }
        /*
        Lua::set_integer ("seeker_count", sc);
        Lua::set_integer ("flag_count", fc);
        */

        return NULL;
    }
};


int main(int argc, char **argv) {
    // setting debug output messages
    Logger :: set_level ( Logger :: DEBUG );

    LOG << "RTSAI testing application" << std::endl;
    if (argc > 1) {
        gamefile = argv[1];
        Game::getInstance().init(gamefile);

        // adding handler to the game events
        EventHandle handler;
        GameEvent *flag_event = Game::getInstance().get_event ( "flag_captured" );
        flag_event->add_listener ( &handler );

        // starting the game
        GameView :: init ( argc, argv, view_update );
        GameView :: start_loop();
    }
    else {
        LOG << "Usage: rtsai <game_description_file.lua>" << std::endl;
        exit(1);
    }
}
